package com.mallcloud.mall.app.service.impl;

import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mallcloud.mall.app.api.constant.ApiConstants;
import com.mallcloud.mall.app.api.entity.dto.AppMmParkingPayInfoDTO;
import com.mallcloud.mall.app.api.entity.vo.MmParkingResponseVO;
import com.mallcloud.mall.app.config.ParkConfig;
import com.mallcloud.mall.app.service.AppMmParkingService;
import com.mallcloud.mall.app.service.AppParkingCouponService;
import com.mallcloud.mall.app.utils.SignUtils;
import com.mallcloud.mall.common.core.constant.enums.RLockEnum;
import com.mallcloud.mall.common.core.constant.enums.mall.OrderEnum;
import com.mallcloud.mall.common.core.exception.FailException;
import com.mallcloud.mall.common.core.util.HttpUtil;
import com.mallcloud.mall.mall.api.entity.MallOrderCouponModel;
import com.mallcloud.mall.mall.api.entity.dto.BackFeeOrderInfo;
import com.mallcloud.mall.mall.api.entity.dto.ParkingPaymentInfo;
import com.mallcloud.mall.mall.api.entity.dto.PayParkingFeeDTO;
import com.mallcloud.mall.mall.api.entity.dto.PlateInfo;
import com.mallcloud.mall.mall.service.MallOrderCouponService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringEscapeUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 *
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
public class AppMmParkingServiceImpl implements AppMmParkingService {
	private final RedisTemplate redisTemplate;
	private final HttpUtil httpUtil;
	private final ParkConfig parkConfig;
	private final AppParkingCouponService appParkingCouponService;
	private final MallOrderCouponService mallOrderCouponService;

	@SneakyThrows
	@Override
	public ParkingPaymentInfo getParkingPaymentInfo(String plateNo) {
		JSONObject requestBody = getRequestParams(ApiConstants.MmApi.GET_PARKING_PAYMENT_INFO.getServiceCode());
		requestBody.put("plateNo", plateNo);
		requestBody.put("key", SignUtils.paramsSign(requestBody, parkConfig.getAppSecret()));

		MmParkingResponseVO commonResult = httpUtil.exchange(
				ApiConstants.MmApi.GET_PARKING_PAYMENT_INFO.getUrl(),
				ApiConstants.MmApi.GET_PARKING_PAYMENT_INFO.getMethod(),
				ApiConstants.MmApi.header,
				null,
				requestBody,
				ApiConstants.MmApi.GET_PARKING_PAYMENT_INFO.getResponseClass()
		);
		log.info("停车账单返回:{}", JSONObject.toJSONString(commonResult));
		if (Objects.isNull(commonResult) || 0 != commonResult.getResCode()) {
			throw new FailException(commonResult.getResMsg());
		}
		ParkingPaymentInfo parkingPaymentInfo = JSONObject.toJavaObject(JSONObject.parseObject(commonResult.getData()), ParkingPaymentInfo.class);
		//账单号（订单号5分钟内有效）
		redisTemplate.opsForValue().set(RLockEnum.MM_ORDER_TIMEOUT.getKey(parkingPaymentInfo.getOrderNo()), 1, 4, TimeUnit.MINUTES);
		return parkingPaymentInfo;
	}

	@SneakyThrows
	@Override
	public JSONObject payParkingFee(PayParkingFeeDTO payParkingFeeDto) {
		long amount = 0;
		BigDecimal finalMoney = NumberUtil.sub(payParkingFeeDto.getPayableAmount(), payParkingFeeDto.getFreeMoney());
		if (finalMoney.compareTo(BigDecimal.ZERO) == 1) {
			amount = finalMoney.longValue();//支付金额(不包含减免部分),单位为分，不允许为空
		}
		JSONObject requestBody = getRequestParams(ApiConstants.MmApi.PAY_PARKING_FEE.getServiceCode());
		requestBody.put("orderNo", payParkingFeeDto.getOrderNo());
		requestBody.put("payableAmount", payParkingFeeDto.getPayableAmount());//应付金额
		requestBody.put("amount", amount);
		requestBody.put("payType", payParkingFeeDto.getPayType());
		requestBody.put("payMethod", payParkingFeeDto.getPayMethod());
		requestBody.put("freeMoney", payParkingFeeDto.getFreeMoney());
		requestBody.put("freeTime", payParkingFeeDto.getFreeTime());
		if (payParkingFeeDto.getFreeMoney().intValue() > 0) {
			requestBody.put("freeDetail", JSON.toJSONString(payParkingFeeDto.getFreeDetails()));
		}
		requestBody.put("key", SignUtils.paramsSign(requestBody, parkConfig.getAppSecret()));

		MmParkingResponseVO commonResult = httpUtil.exchange(
				ApiConstants.MmApi.PAY_PARKING_FEE.getUrl(),
				ApiConstants.MmApi.PAY_PARKING_FEE.getMethod(),
				ApiConstants.MmApi.header,
				null,
				requestBody,
				ApiConstants.MmApi.PAY_PARKING_FEE.getResponseClass()
		);
		log.info("停车费支付返回:{}", JSONObject.toJSONString(commonResult));
		if (Objects.isNull(commonResult) || 0 != commonResult.getResCode()) {
			throw new Exception(commonResult.getResMsg());
		}
		return JSONObject.parseObject(commonResult.getData());
	}

	/**
	 * 回滚目前对过程不起作用，因为过程里面已经做了提交
	 *
	 * @param dto
	 * @return
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public Boolean payRecordReporting(AppMmParkingPayInfoDTO dto) {
		// 新增订单
		if (Objects.nonNull(dto.getOrder())) {
			log.info("保存订单参数：{}", JSON.toJSONString(dto.getOrder()));
			// 如果订单保存了之后，前端唤起支付那里失败，再次支付就会触发订单号唯一限制的报错，所以这里先删除，再保存
			mallOrderCouponService.remove(new LambdaQueryWrapper<MallOrderCouponModel>()
					.eq(MallOrderCouponModel::getOrderNo, dto.getOrder().getOrderNo())
					.eq(MallOrderCouponModel::getOrderType, OrderEnum.TypeEnum.ORDER_PARK.getType())
			);
			mallOrderCouponService.save(dto.getOrder());
		}
		try {
			// 积分抵扣
			if (Objects.nonNull(dto.getParkingPointsPayDiscount())) {
				appParkingCouponService.parkingPointsDiscount(dto.getParkingPointsPayDiscount());
			}
			// 券核销
			if (Objects.nonNull(dto.getProParkingCouponWriteOff())) {
				appParkingCouponService.parkingCouponWriteOff(dto.getProParkingCouponWriteOff());
			}
			// 总支付金额=0 的时候才会传
			// 停车支付-用作停车支付上报与抬杆
			if (Objects.nonNull(dto.getPayParkingFee())) {
				log.info("停车支付参数：{}", JSON.toJSONString(dto.getPayParkingFee()));
				this.payParkingFee(dto.getPayParkingFee());
			}
		}
		catch (Exception e) {
			log.error(e.getMessage(), e);
			if (Objects.nonNull(dto.getParkingPointsPayDiscount())) {
				// 停车积分-抵扣费冲正
				appParkingCouponService.parkingPointsDiscountReversal(dto.getParkingPointsPayDiscount());
			}
			if (Objects.nonNull(dto.getProParkingCouponWriteOff())) {
				// 停车券-核销冲正
				appParkingCouponService.parkingCouponReversal(dto.getProParkingCouponWriteOff());
			}
			throw new FailException(e.getMessage(), e);
		}
		return Boolean.TRUE;
	}

	/**
	 * 公共请求参数
	 * @param serviceCode
	 * @return
	 */
	private JSONObject getRequestParams(String serviceCode) {
		JSONObject requestBody = new JSONObject();
		requestBody.put("parkId", parkConfig.getParkId());
		requestBody.put("serviceCode", serviceCode);
		requestBody.put("ts", System.currentTimeMillis());
		requestBody.put("reqId", UUID.randomUUID().toString());
		requestBody.put("appId", parkConfig.getAppId());
		return requestBody;
	}

	@SneakyThrows
	@Override
	public List<BackFeeOrderInfo> getBackFeeOrderInfo(List<String> plateNoList) {
		List<BackFeeOrderInfo> backFeeOrderInfoList = new ArrayList<>();
		for (String plateNo : plateNoList) {
			if (StrUtil.isBlank(plateNo)) {
				continue;
			}
			JSONObject requestBody = getRequestParams("getBackFeeOrderInfo");
			requestBody.put("plateNo", plateNo);
			requestBody.put("key", SignUtils.paramsSign(requestBody, parkConfig.getAppSecret()));

			MmParkingResponseVO commonResult = httpUtil.exchange(
					ApiConstants.MmApi.GET_BACK_FEE_ORDER_INFO.getUrl(),
					ApiConstants.MmApi.GET_BACK_FEE_ORDER_INFO.getMethod(),
					ApiConstants.MmApi.GET_BACK_FEE_ORDER_INFO.header,
					null,
					requestBody,
					ApiConstants.MmApi.GET_BACK_FEE_ORDER_INFO.getResponseClass()
			);
			log.info("账单查询返回:{}", JSONObject.toJSONString(commonResult));
			if (Objects.isNull(commonResult) || 0 != commonResult.getResCode()) {
				continue;
			}
			BackFeeOrderInfo parkingPaymentInfo = JSONObject.toJavaObject(JSONObject.parseObject(commonResult.getData()), BackFeeOrderInfo.class);
			backFeeOrderInfoList.add(parkingPaymentInfo);
		}
		return backFeeOrderInfoList;
	}

//	//缴费记录上报
//	@SneakyThrows
//	@Override
//	public void paymentRecordReporting(PayParkingFeeDTO payParkingFeeDto) {
//		JSONObject requestBody = new JSONObject();
//		requestBody.put("parkId", parkConfig.getParkId());
//		requestBody.put("ts", System.currentTimeMillis());
//		requestBody.put("reqId", UUID.randomUUID().toString());
//		requestBody.put("appId", parkConfig.getAppId());
//
//		requestBody.put("plateNo", payParkingFeeDto.getPlateNo());
//		requestBody.put("billId", payParkingFeeDto.getOrderNo());
//		requestBody.put("entryTime", payParkingFeeDto.getEntryTime());
//		requestBody.put("payTime", payParkingFeeDto.getPayTime());
//		requestBody.put("paySource", "");//支付来源枚举 对接时由科拓提供
//		requestBody.put("payType", payParkingFeeDto.getPayType());
//		requestBody.put("payMethod", payParkingFeeDto.getPayMethod());
//		requestBody.put("totalMoney", payParkingFeeDto.getPayableAmount());//应收总金额
//		requestBody.put("paidMoney", payParkingFeeDto.getPayableAmount());//实收总金额
//		requestBody.put("freeTime", payParkingFeeDto.getFreeTime());//抵扣时长
//		requestBody.put("freeMoney", payParkingFeeDto.getFreeMoney());//抵扣金额
//
//		httpUtil.exchange(
//				ApiConstants.MmApi.POST_PAY_FEE_INFO.getUrl(),
//				ApiConstants.MmApi.POST_PAY_FEE_INFO.getMethod(),
//				ApiConstants.MmApi.header,
//				null,
//				requestBody,
//				ApiConstants.MmApi.POST_PAY_FEE_INFO.getResponseClass()
//		);
//	}

	@SneakyThrows
	@Override
	public List<PlateInfo> paymentRecordList(List<String> plateNoList) {
		List<PlateInfo> PlateInfoList = new ArrayList<>();
		for (String plateNo : plateNoList) {
			JSONObject requestBody = getRequestParams(ApiConstants.MmApi.GET_PARKING_PAYMENT_LIST.getServiceCode());
			requestBody.put("pageIndex", 1);
			requestBody.put("pageSize", 15);
			requestBody.put("plateNo", plateNo);
			requestBody.put("key", SignUtils.paramsSign(requestBody, parkConfig.getAppSecret()));

			MmParkingResponseVO commonResult = httpUtil.exchange(
					ApiConstants.MmApi.GET_PARKING_PAYMENT_LIST.getUrl(),
					ApiConstants.MmApi.GET_PARKING_PAYMENT_LIST.getMethod(),
					ApiConstants.MmApi.header,
					null,
					requestBody,
					ApiConstants.MmApi.GET_PARKING_PAYMENT_LIST.getResponseClass()
			);
			log.info("查询缴费记录返回:{}", JSONObject.toJSONString(commonResult));
			if (Objects.isNull(commonResult) || 0 != commonResult.getResCode()) {
				throw new FailException(commonResult.getResMsg());
			}
			JSONObject data = JSONObject.parseObject(StringEscapeUtils.escapeJson(commonResult.getData()));
			if (data.getInteger("totalCount") > 0) {
				JSONArray plateInfoArr = data.getJSONArray("plateList");
				for (int i = 0; i < plateInfoArr.size(); i++) {
					PlateInfo plateInfo = JSONObject.toJavaObject(plateInfoArr.getJSONObject(i), PlateInfo.class);
					PlateInfoList.add(plateInfo);
				}
			}
		}
		return PlateInfoList;
	}
}